/*
 * MCU.c
 *
 * Created on: 2021-12-1
 *     Author: tangjie
 */

#include "MCU.h"
#include "clockMan1.h"
#include "pin_mux.h"
#include "Tps929120.h"
#include "Tps929120_PBCfg.h"
#include "General.h"
#include "Driver.h"
#include <string.h>
#include "SysCommon.h"

/*******************************************************************************
 * Definitions
 ******************************************************************************/
#define LPIT_CHANNEL        0UL

/* (CLK (MHz)* timer period (us) / Prescaler) */
#define TIMER_COMPARE_VAL             (uint16_t)(500U)
#define TIMER_TICKS_1US               (uint16_t)(1U)

/*******************************************************************************
 * Variables
 ******************************************************************************/

static ftm_state_t ftm1StateStruct;
static uint8_t g_u8rcvBuffer[16];
static volatile uint16_t capturedValue = 0U;
static uint16_t s_u16timerOverflowInterruptCount = 0U;
static uint8_t s_u8receiveByteNum = 0;
static uint8_t volatile s_u8timeOutFlag = 0;
  
#if CURRENT_PROJECT  == PROJECT_trunk
uint8_t sw_version_buff[8] = {0x14, 0x19, 0x2, 0x18, 0x56, 0x1, 0x2E, 0x2};
uint8_t sw_version_buff2[8] = {0x43, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
#endif

#if CURRENT_PROJECT  == PROJECT_Fender_Left
uint8_t sw_version_buff[8] = {0x14, 0x19, 0x2, 0x18, 0x56, 0x1, 0x2E, 0x2};
uint8_t sw_version_buff2[8] = {0x41, 0x4C, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
#endif

#if CURRENT_PROJECT  == PROJECT_Fender_Right
uint8_t sw_version_buff[8] = {0x14, 0x19, 0x2, 0x18, 0x56, 0x1, 0x2E, 0x2};
uint8_t sw_version_buff2[8] = {0x41, 0x52, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
#endif


/*******************************************************************************
 * Static Functions
 ******************************************************************************/
static void rxCallback(void *driverState, uart_event_t event, void *userData)
{
    /* Unused parameters */
    (void)driverState;
    (void)userData;

    /* Check the event type */
    if (event == UART_EVENT_RX_FULL)
    {
		s_u8receiveByteNum++;
		LPUART_DRV_SetRxBuffer(INST_LPUART1, &g_u8rcvBuffer[s_u8receiveByteNum], 1U);
    }
}


static uint32_t timerGetTimeIntervalCallback0(uint32_t *ns)
{
    static uint32_t previousCountValue = 0UL;
    uint32_t counterValue;
    counterValue = capturedValue;
    *ns = ((uint32_t)(counterValue + s_u16timerOverflowInterruptCount * TIMER_COMPARE_VAL - previousCountValue)) * 1000UL / TIMER_TICKS_1US;
    s_u16timerOverflowInterruptCount = 0UL;
    previousCountValue = counterValue;
    return 0UL;
}

static void MCU_WDGInit()
{
	WDG_Init(&wdg_pal1_Instance, &wdg_pal1_Config0);
}

static void MCU_ClockInit(void)
{
    CLOCK_SYS_Init(g_clockManConfigsArr,   CLOCK_MANAGER_CONFIG_CNT,
                   g_clockManCallbacksArr, CLOCK_MANAGER_CALLBACK_CNT);
    CLOCK_SYS_UpdateConfiguration(0U, CLOCK_MANAGER_POLICY_FORCIBLE);
}

static void MCU_GpioInit(void)
{
	PINS_DRV_Init(NUM_OF_CONFIGURED_PINS, g_pin_mux_InitConfigArr);
}

static void MCU_LpuartInit()
{
	LPUART_DRV_Init(INST_LPUART1, &lpuart1_State, &lpuart1_InitConfig0);

	INT_SYS_EnableIRQ(LPUART0_RxTx_IRQn);
    INT_SYS_SetPriority(LPUART0_RxTx_IRQn, 0x01);

	LPUART_DRV_InstallRxCallback(INST_LPUART1, rxCallback, NULL);
}


static void LPIT0_ISR_Handle()
{
	Task_TimeTick();
	if(LPIT_DRV_GetInterruptFlagTimerChannels(INST_LPIT1, 1))
	{
		LPIT_DRV_ClearInterruptFlagTimerChannels(INST_LPIT1, 1);
	}
}


static lin_callback_t CallbackHandler(uint32_t instance, lin_state_t * lin1_State)
{
    lin_callback_t callbackCurrent;
    callbackCurrent = lin1_State->Callback;

    switch (lin1_State->currentEventId)
    {
        case LIN_PID_OK:

            /* Set timeout */
            LIN_DRV_SetTimeoutCounter(INST_LIN1, 500U);

			if(0x1 == lin1_State->currentId)
            {
                /* Call to Send Frame DATA Function */
                LIN_DRV_SendFrameData(INST_LIN1, sw_version_buff, sizeof(sw_version_buff));
            }

			if(0x2 == lin1_State->currentId)
            {
                /* Call to Send Frame DATA Function */
                LIN_DRV_SendFrameData(INST_LIN1, sw_version_buff2, sizeof(sw_version_buff2));
            }

            break;
        case LIN_PID_ERROR:
            /* Go to idle mode */
            LIN_DRV_GoToSleepMode(INST_LIN1);
            break;
        case LIN_TX_COMPLETED:
        case LIN_RX_COMPLETED:
            /* Go to idle mode */
            LIN_DRV_GotoIdleState(INST_LIN1);
            break;
        case LIN_CHECKSUM_ERROR:
        case LIN_READBACK_ERROR:
        case LIN_FRAME_ERROR:
        case LIN_RECV_BREAK_FIELD_OK:
            /* Set timeout */
            LIN_DRV_SetTimeoutCounter(INST_LIN1, 500);
            break;
        case LIN_WAKEUP_SIGNAL:
            break;
        case LIN_SYNC_ERROR:
        case LIN_BAUDRATE_ADJUSTED:
        case LIN_NO_EVENT:
        case LIN_SYNC_OK:
        default:
        /* do nothing */
            break;
    }
    return callbackCurrent;
}

static void MCU_LpitInit()
{
    /* Initialize LPIT instance 0
     *  -   Reset and enable peripheral
     */
    LPIT_DRV_Init(INST_LPIT1, &lpit1_InitConfig);
    /* Initialize LPIT channel 0 and configure it as a periodic counter
     * which is used to generate an interrupt every second.
     */
    LPIT_DRV_InitChannel(INST_LPIT1, 0, &lpit1_ChnConfig0);

    /* Install LPIT_ISR as LPIT interrupt handler */
    INT_SYS_InstallHandler(LPIT0_IRQn, &LPIT0_ISR_Handle, (isr_t *)0);

	/* Start LPIT0 channel 0 counter */
    LPIT_DRV_StartTimerChannels(INST_LPIT1, (1 << 0));
}

static void LPTMR_ISR(void)
{
	LPTMR_DRV_StopCounter(INST_LPTMR1);
	
    /* Clear compare flag */
    LPTMR_DRV_ClearCompareFlag(INST_LPTMR1);

	s_u8timeOutFlag = 1;
}

static void MCU_LptmrInit(void)
{
	LPTMR_DRV_Init(INST_LPTMR1, &lpTmr1_config0, false);

    /* Install IRQ handler for LPTMR interrupt */
    INT_SYS_InstallHandler(LPTMR0_IRQn, &LPTMR_ISR, (isr_t *)0);
    /* Enable IRQ for LPTMR */
    INT_SYS_EnableIRQ(LPTMR0_IRQn);
}

static void MCU_ADCInit(void)
{
   	ADC_DRV_ConfigConverter(INST_ADCONV1, &adConv1_ConvConfig0);
    ADC_DRV_AutoCalibration(INST_ADCONV1);
}

static void MCU_PWMInit(void)
{
	PWM_Init(&pwm_pal1Instance, &pwm_pal1Configs);
}


static void MCU_FTMInit(void)
{
	FTM_DRV_Init(INST_FLEXTIMER_IC1, &flexTimer_ic1_InitConfig, &ftm1StateStruct);
	FTM_DRV_InitInputCapture(INST_FLEXTIMER_IC1, &flexTimer_ic1_InputCaptureConfig2);
}



static void MCU_LinInit(void)
{
    /* Initialize LIN network interface */
    LIN_DRV_Init(INST_LIN1, &lin1_InitConfig0, &lin1_State);

    /* Install callback function */
    LIN_DRV_InstallCallback(INST_LIN1, (lin_callback_t)CallbackHandler);
}



/*Functions********************************************************************/
void uartWrite(uint8_t commandFrame[], uint8_t frameLength, uint8_t checkResponse, uint8_t responseLength)
{
	uint8_t i =0;

	if(checkResponse != 0)
	{
		LPUART_DRV_ReceiveData(INST_LPUART1, g_u8rcvBuffer, 1);
	}
	else
	{
		LPUART_DRV_AbortReceivingData(INST_LPUART1);
	}
    

	LPUART_DRV_SendDataBlocking(INST_LPUART1, commandFrame, frameLength, 2);

	if(checkResponse == TRUE)
	{
		 /* launch timer and set wait time = 2000us
	      * This time should be larger than the time to receive all the response bytes,
	      * And the response receiving time depends on the buard rate and the number of response byte,
	      * For example, baurd rate = 500000, 2 response byte, so the wait time should be larger than 2*10*1/500000 = 40us
	      * Why 2*10 because for each byte there are additional 1 start bit and 1 stop bit
	      */
		timeOut(2000);
		/* received all response byte or the wait time exceeds the specified time */
		while(!((s_u8timeOutFlag == 1) || (s_u8receiveByteNum == responseLength)));

		/*Take some action when successfully received response*/
		if(s_u8receiveByteNum == responseLength)
		{
			/* Toggle Green LED */
			LPUART_DRV_AbortReceivingData(INST_LPUART1);

#if CURRENT_PROJECT  == PROJECT_trunk
			if(g_u8rcvBuffer[1] == TPS_CHIP_ADD_14)
			{
				memcpy(g_u8Diag_Databuff, g_u8rcvBuffer, responseLength);
			}

			if(g_u8rcvBuffer[1] == TPS_CHIP_ADD_15)
			{
				memcpy(g_u8Diag_Databuff_Right, g_u8rcvBuffer, responseLength);
			}
#endif

#if ((CURRENT_PROJECT  == PROJECT_Fender_Left)|| (CURRENT_PROJECT  == PROJECT_Fender_Right))
			if(g_u8rcvBuffer[1] == TPS_CHIP_ADD_2)
			{
				memcpy(g_u8Diag_Databuff, g_u8rcvBuffer, responseLength);
			}
#endif
		}
		else
		{
			if((responseLength - s_u8receiveByteNum) >= 2)
			{
#if CURRENT_PROJECT  == PROJECT_trunk
				if(g_u8rcvBuffer[1] == TPS_CHIP_ADD_14)
				{
					g_u8Diag_Databuff[7] = 0xFF;
					memcpy(g_u8Diag_Databuff, g_u8rcvBuffer, s_u8receiveByteNum);
				}
				if(g_u8rcvBuffer[1] == TPS_CHIP_ADD_15)
				{
					g_u8Diag_Databuff_Right[7] = 0xFF;
					memcpy(g_u8Diag_Databuff_Right, g_u8rcvBuffer, s_u8receiveByteNum);
				}
#endif

#if ((CURRENT_PROJECT  == PROJECT_Fender_Left)|| (CURRENT_PROJECT  == PROJECT_Fender_Right))
				if(g_u8rcvBuffer[1] == TPS_CHIP_ADD_2)
				{
					g_u8Diag_Databuff[7] = 0xFF;
					memcpy(g_u8Diag_Databuff, g_u8rcvBuffer, s_u8receiveByteNum);
				}
#endif
			}
		}

		/* Clear data sent */
		for(i=0; i<frameLength; i++)
		{
			// commandFrame[i] = 0x00;
		}
		/* Clear response data*/
		for(i=0; i<responseLength; i++)
		{
			g_u8rcvBuffer[i] = 0x00;
		}
		/* reset number of response data*/
		s_u8receiveByteNum = 0;

		/* Disable the receiver and receive data full interrupt of LPUART1 */
		LPUART_DRV_AbortReceivingData(INST_LPUART1);

	}
}

void MCU_FeedWdg()
{
	WDG_Refresh(&wdg_pal1_Instance);
}

void timeOut(uint32_t timeOut)
{
	/* Clear flag */
	s_u8timeOutFlag=0;
	/* Set time of timeout */
	LPTMR_DRV_SetCompareValueByUs(INST_LPTMR1, timeOut);

	LPTMR_DRV_StartCounter(INST_LPTMR1);
}

void MCU_Init(void)
{
	INT_SYS_DisableIRQGlobal();
	MCU_WDGInit();
	MCU_ClockInit();
	MCU_GpioInit();
	MCU_LpuartInit();
	MCU_LinInit();

	LPUART_DRV_Deinit(INST_LPUART1);
	LIN_DRV_Deinit(INST_LIN1);
	
	MCU_LptmrInit();
	MCU_LpitInit();
	MCU_ADCInit();
	MCU_PWMInit();
	MCU_FTMInit();
	MCU_FeedWdg();
	MCU_LpuartInit();
	MCU_LinInit();
	INT_SYS_EnableIRQGlobal();
}
